

#include <math.h>

#ifdef _WINDOWS
#include <windows.h>
#endif

#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glut.h>

#include "glfont.h"


#include "aplicationdraw.h"


#define NUM_HATCHES  6
#define HATCH_WIDTH  8
#define HATCH_HEIGHT 16
/*
** 6 padroes pre-definidos a serem acessados atraves de cdHatch(
   CD_HORIZONTAL | CD_VERTICAL | CD_FDIAGONAL | CD_BDIAGONAL |
   CD_CROSS      | CD_DIAGCROSS)

*/
static GLubyte gra_hatches[NUM_HATCHES][HATCH_WIDTH*HATCH_HEIGHT] = {
  {0xFF,0xFF,0xFF,0xFF,  /* HORIZONTAL */
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0xFF,0xFF,0xFF,0xFF,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0xFF,0xFF,0xFF,0xFF,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0xFF,0xFF,0xFF,0xFF,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00,
   0x00,0x00,0x00,0x00},
  {0x22,0x22,0x22,0x22,  /* VERTICAL */
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22,
   0x22,0x22,0x22,0x22},
  {0x01,0x01,0x01,0x01,  /* FDIAGONAL */
   0x02,0x02,0x02,0x02,
   0x04,0x04,0x04,0x04,
   0x08,0x08,0x08,0x08,
   0x10,0x10,0x10,0x10,
   0x20,0x20,0x20,0x20,
   0x40,0x40,0x40,0x40,
   0x80,0x80,0x80,0x80,
   0x01,0x01,0x01,0x01,
   0x02,0x02,0x02,0x02,
   0x04,0x04,0x04,0x04,
   0x08,0x08,0x08,0x08,
   0x10,0x10,0x10,0x10,
   0x20,0x20,0x20,0x20,
   0x40,0x40,0x40,0x40,
   0x80,0x80,0x80,0x80,
   0x01,0x01,0x01,0x01,
   0x02,0x02,0x02,0x02,
   0x04,0x04,0x04,0x04,
   0x08,0x08,0x08,0x08,
   0x10,0x10,0x10,0x10,
   0x20,0x20,0x20,0x20,
   0x40,0x40,0x40,0x40,
   0x80,0x80,0x80,0x80,
   0x01,0x01,0x01,0x01,
   0x02,0x02,0x02,0x02,
   0x04,0x04,0x04,0x04,
   0x08,0x08,0x08,0x08,
   0x10,0x10,0x10,0x10,
   0x20,0x20,0x20,0x20,
   0x40,0x40,0x40,0x40,
   0x80,0x80,0x80,0x80},
  {0x80,0x80,0x80,0x80,  /* BDIAGONAL */
   0x40,0x40,0x40,0x40,
   0x20,0x20,0x20,0x20,
   0x10,0x10,0x10,0x10,
   0x08,0x08,0x08,0x08,
   0x04,0x04,0x04,0x04,
   0x02,0x02,0x02,0x02,
   0x01,0x01,0x01,0x01,
   0x80,0x80,0x80,0x80,
   0x40,0x40,0x40,0x40,
   0x20,0x20,0x20,0x20,
   0x10,0x10,0x10,0x10,
   0x08,0x08,0x08,0x08,
   0x04,0x04,0x04,0x04,
   0x02,0x02,0x02,0x02,
   0x01,0x01,0x01,0x01,
   0x80,0x80,0x80,0x80,
   0x40,0x40,0x40,0x40,
   0x20,0x20,0x20,0x20,
   0x10,0x10,0x10,0x10,
   0x08,0x08,0x08,0x08,
   0x04,0x04,0x04,0x04,
   0x02,0x02,0x02,0x02,
   0x01,0x01,0x01,0x01,
   0x80,0x80,0x80,0x80,
   0x40,0x40,0x40,0x40,
   0x20,0x20,0x20,0x20,
   0x10,0x10,0x10,0x10,
   0x08,0x08,0x08,0x08,
   0x04,0x04,0x04,0x04,
   0x02,0x02,0x02,0x02,
   0x01,0x01,0x01,0x01},
  {0xFF,0xFF,0xFF,0xFF,  /* CROSS */
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0xFF,0xFF,0xFF,0xFF,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00,
   0x20,0x00,0x20,0x00},
  {0x80,0x00,0x80,0x00,  /* DIAGCROSS */
   0x40,0x01,0x40,0x01,
   0x20,0x02,0x20,0x02,
   0x10,0x04,0x10,0x04,
   0x08,0x08,0x08,0x08,
   0x04,0x10,0x04,0x10,
   0x02,0x20,0x02,0x20,
   0x01,0x40,0x01,0x40,
   0x00,0x80,0x00,0x80,
   0x01,0x40,0x01,0x40,
   0x02,0x20,0x02,0x20,
   0x04,0x10,0x04,0x10,
   0x08,0x08,0x08,0x08,
   0x10,0x04,0x10,0x04,
   0x20,0x02,0x20,0x02,
   0x40,0x01,0x40,0x01,
   0x80,0x00,0x80,0x00,
   0x40,0x01,0x40,0x01,
   0x20,0x02,0x20,0x02,
   0x10,0x04,0x10,0x04,
   0x08,0x08,0x08,0x08,
   0x04,0x10,0x04,0x10,
   0x02,0x20,0x02,0x20,
   0x01,0x40,0x01,0x40,
   0x00,0x80,0x00,0x80,
   0x01,0x40,0x01,0x40,
   0x02,0x20,0x02,0x20,
   0x04,0x10,0x04,0x10,
   0x08,0x08,0x08,0x08,
   0x10,0x04,0x10,0x04,
   0x20,0x02,0x20,0x02,
   0x40,0x01,0x40,0x01}
};

#define GRA_RAD2DEG  57.296

#define Box(x1,y1,x2,y2)        {glBegin( GL_LINE_LOOP );\
  glVertex2i( (x1), (y1) );\
  glVertex2i( (x2), (y1) );\
  glVertex2i( (x2), (y2) );\
  glVertex2i( (x1), (y2) );\
  glEnd( );}

#define Poly(pt,n)              {int i;\
  glBegin( GL_POLYGON );\
  for (i=0;i<n;i++)\
  glVertex2d( pt[i*2+0], pt[i*2+1] );\
  glEnd( );}

#define inLine( x1, y1, x2, y2) { glBegin( GL_LINE_STRIP );\
  glVertex2i( x1, y1 );\
  glVertex2i( x2, y2 );\
  glEnd( ); }

#define floatLine( x1, y1, x2, y2) { glBegin( GL_LINE_STRIP );\
  glVertex2f( x1, y1 );\
  glVertex2f( x2, y2 );\
  glEnd( ); }

#define in(a,b) ((big ^ (a > 0 && b < 0)) || (!a && !b))

/* macros do _gra2dArc */
#define arcPixel(_x, _y)        {glBegin( GL_POINTS );          \
  glVertex2i( _x, _y );     \
  glEnd( );}

/* plota os quatro pontos simetricos */
#define Four() \
  if (in(ta1,ta2)) arcPixel(px1, py1); \
  if (in(tc1,tc2)) arcPixel(px2, py2); \
  if (in(tb1,tb2)) arcPixel(px2, py1); \
  if (in(td1,td2)) arcPixel(px1, py2);
#define Two() \
  if (in(ta1,ta2)) arcPixel(px1, py1); \
  if (in(tc1,tc2)) arcPixel(px2, py2);
#define One() \
  if (in(ta1,ta2)) arcPixel(px1, py1);
#define reduce(a)                            \
  {double t=a/360;                           \
  a=(t>=0)?a-((int)t)*360:a+((int)t+1)*360;}

/* Macros usadas pela funcao cdSimSector.*/
#define LinesX()      \
  if (big)            \
  {                   \
  double t;         \
  t = r1x;         \
  r1x = r2x;       \
  r2x = t;          \
  t = r1y;          \
  r1y = r2y;        \
  r2y = t;          \
}                   \
  if (in(ta1,ta2)&&in(tb1,tb2)) \
  {       /* Os dois dentro           */       \
  if ((int)r1y != (int)y || (int)r2y != (int)y) /* Nao intersecta retas */ \
    {\
    inLine(px1, py1, px2, py1);     \
}\
    else \
    {                              /* Intersecta as duas retas */       \
    inLine(px1, py1, (int)r2x+xc, py1);      \
    inLine(px2, py1, (int)r1x+xc, py1);     \
}                                        \
}                                          \
  else if (in(ta1,ta2))                      \
  {                              \
  inLine(px1, py1, (int)r2x+xc, py1);        \
}                                          \
  else if (in(tb1,tb2))                      \
  {                              \
  inLine(px2, py1, (int)r1x+xc, py1);        \
}                                          \
  else if ((int)r1y == (int)y && (int)r2y == (int)y)/* Intersecta as duas retas*/       \
  {                              \
  inLine((int)r1x+xc, py1, (int)r2x+xc, py1);  /* agora a de baixo */       \
}                                          \
  \
  if (in(tc1,tc2)&&in(td1,td2)) \
  {       /* Os dois dentro          */       \
  if ((int)r1y != (int)-y || (int)r2y != (int)-y) /* Nao intersecta retas */ \
    {\
    inLine(px1, py2, px2, py2);              \
}\
    else \
    {                              /* Intersecta as duas retas */      \
    inLine(px1, py2, (int)r2x+xc, py2);      \
    inLine(px2, py2, (int)r1x+xc, py2);      \
}                                        \
}                                          \
  else if (in(td1,td2))                      \
  {                              \
  inLine(px1, py2, (int)r1x+xc, py2);        \
}                                          \
  else if (in(tc1,tc2))                      \
  {                              \
  inLine(px2, py2, (int)r2x+xc, py2);        \
}                                          \
  else if ((int)r1y == (int)-y && (int)r2y == (int)-y)/*Intersecta as duas retas */     \
  {                              \
  inLine((int)r1x+xc, py2, (int)r2x+xc, py2);\
}                                          

#define LineX()     \
  if (in(ta1,ta2))  inLine(xc, yc, px1, yc);  \
  if (in(tb1,tb2))  inLine(xc, yc, px2, yc);  



//
//////////////////////////////////////////////////////////////////////////
static void _gra2dArc(int xc, int yc, int width, int height, double angle1, double angle2);
static void _gra2dSector( int xc, int yc, int width, int height, double angle1, double angle2 );
static void GraSetRasterDspMode( void );
static void GraResetRasterDspMode( void );




//
//////////////////////////////////////////////////////////////////////////
aplicationdraw::aplicationdraw(void)
{
  fill_style = draw_HOLLOW;     
  gra_mark_type = draw_POINT;  
  gra_mark_size = 4;
  ref_size = 10.0;

  // glutInit(NULL, NULL);
}

aplicationdraw::aplicationdraw( void *currPainter )
{
  painter = currPainter;

  fill_style = draw_HOLLOW;     
  gra_mark_type = draw_POINT;  
  gra_mark_size = 4; 
}
//
//////////////////////////////////////////////////////////////////////////
aplicationdraw::~aplicationdraw(void)
{
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::setCanvas (void *currPainter )
{
  painter = currPainter;
}


//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::PolyLine( int n, double *pt )
{
  glBegin( GL_LINE_STRIP );
  for( int i = 0; i < n; i++ )
    glVertex2d( pt[i*2+0], pt[i*2+1] );
  glEnd( );
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::PolyMark( int n, double *p )
{
  int bottom;
  int top;
  int left;
  int right;
  int size = gra_mark_size;
  int half_size = size/2;
  double x_, y_, z_;
  int x, y;

  for( int i = 0; i < n; i++ )
  {
    // transform to raster position
    wcCanvas( p[i*2+0], p[i*2+1], 0.0, &x_, &y_, &z_ );
    x = (int) x_;
    y = (int) y_;

    bottom = y - half_size;
    top    = y + half_size;
    left   = x - half_size;
    right  = x + half_size;

    /* Put the viewport in raster coordinates */
    GraSetRasterDspMode( );

    /* Draw the mark */
    switch( gra_mark_type )
    {
    case draw_POINT:
      glBegin( GL_POINTS );
      glVertex2i( x, y );
      glEnd( );
      break;
    case draw_STAR:
      inLine( left, bottom, right, top );
      inLine( left, top, right, bottom );
      /* continue */
    case draw_PLUS:
      inLine( left, y, right, y );
      inLine( x, bottom, x, top );
      break;
    case draw_HOLLOW_CIRCLE:
      _gra2dArc( x, y, size, size, 0, 360 );
      break;
    case draw_HOLLOW_BOX:
      Box( left, bottom, right, top );
      break;
    case draw_HOLLOW_DIAMOND:
      inLine( left, y, x, top );
      inLine( x, top, right, y );
      inLine( right, y, x, bottom );
      inLine( x, bottom, left, y );
      break;
    case draw_X:
      inLine( left, bottom, right, top );
      inLine( left, top, right, bottom );
      break;
    case draw_CIRCLE:
      _gra2dSector( x, y, size, size, 0, 360 );
      break;
    case draw_BOX:
      glRecti( left, bottom, right, top );
      break;
    case draw_DIAMOND:
      {
        double poly[8];
        poly[0] = left;
        poly[1] = y;
        poly[2] = x;
        poly[3] = top;
        poly[4] = right;
        poly[5] = y;
        poly[6] = x;
        poly[7] = bottom;
        Poly( poly, 4 );
      }
      break;
    }

    /* Restore martix and old values */
    GraResetRasterDspMode( );


  }

}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::FillArea( int n, double *pt )
{
  int i;
  GLenum poly_type;
  GLdouble v[3];
  static GLUtriangulatorObj *tobj = NULL;

  return;

  /* Verify if is need to create the Tesselation object */
  if( tobj == NULL )
  {
    tobj = gluNewTess( );
#ifdef _UNIX_
    gluTessCallback( tobj, GLU_BEGIN,  (void (*)(void))glBegin );
    gluTessCallback( tobj, GLU_VERTEX, (void (*)(void))glVertex2dv );
    gluTessCallback( tobj, GLU_END, (void (*)(void))glEnd );
#else
    gluTessCallback( tobj, GLU_BEGIN,  (void (__stdcall *)(void)) glBegin     );
    gluTessCallback( tobj, GLU_VERTEX, (void (__stdcall *)(void)) glVertex2dv );
    gluTessCallback( tobj, GLU_END,    glEnd       );
#endif
  }

  switch( fill_style ) 
  {
  case draw_HOLLOW:
    poly_type = GL_LINE_LOOP;
    glBegin( poly_type );
    for( i = 0; i < n; i++ )
      glVertex2d( pt[i*2+0], pt[i*2+1] );
    glEnd( );
    break;

  case draw_PATTERN:
    poly_type = GL_POLYGON;
    // GraPatternFillPoly2D( n, pt );
    break;

  case draw_HATCH:
  case draw_SOLID:
  default:
#if 0
    poly_type = GL_POLYGON;
    gluBeginPolygon( tobj );
    for( i = 0; i < n; i++ )
    {
      v[0] = pt[i*2+0];
      v[1] = pt[i*2+1];
      v[2] = 0.0;
      gluTessVertex( tobj, v, &pt[i] );
    }
    gluEndPolygon( tobj );
#else
    poly_type = GL_LINE_LOOP;
    glBegin( poly_type );
    for( i = 0; i < n; i++ )
      glVertex2d( pt[i*2+0], pt[i*2+1] );
    glEnd( );
    break;
#endif
    break;
  }

}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::text( double x, double y, double z, char *s )
{
  GLenum en = glIsEnabled( GL_LIGHTING );
  if ( en == GL_TRUE )
    glDisable( GL_LIGHTING );

#if 1
  //static int first = 0;

  //if ( first == 0 )
//    glCreateFont( );

  //first = 1;
  int n = strlen (s);
  glRasterPos3d(x, y, 0.0);
  for (int i = 0; i < n; ++i)
    glutBitmapCharacter(GLUT_BITMAP_HELVETICA_12, s[i]);


#else
  glListBase( 1 );

  glRasterPos2d ( p[0], p[1] );
  glCallLists ( (GLsizei)strlen(s), GL_UNSIGNED_BYTE, s );

#endif


  if ( en == GL_TRUE )
    glEnable( GL_LIGHTING );

}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetFillIntStyle( int style )
{
  fill_style = style;
  switch( style )
  {
  case draw_HOLLOW:
    glDisable( GL_POLYGON_STIPPLE );
    glDisable( GL_TEXTURE_2D );
    break;

  case draw_SOLID:
    glDisable( GL_POLYGON_STIPPLE );
    glDisable( GL_TEXTURE_2D );
    break;

  case draw_PATTERN:
    glDisable( GL_POLYGON_STIPPLE );
    glEnable( GL_TEXTURE_2D );
    break;

  case draw_HATCH:
    glEnable( GL_POLYGON_STIPPLE );
    glDisable( GL_TEXTURE_2D );
    glPolygonStipple ( gra_hatches[0] );
    break;

  }

}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetHatchStyle( int style )
{
  //QBrush qb = painter->brush();

  //switch (style)
  //{
  //case draw_HORIZONTAL: qb.setStyle(Qt::HorPattern); break;
  //case draw_VERTICAL:   qb.setStyle(Qt::VerPattern); break;
  //case draw_FDIAGONAL:  qb.setStyle(Qt::FDiagPattern); break;
  //case draw_BDIAGONAL:  qb.setStyle(Qt::BDiagPattern); break;
  //case draw_CROSS:      qb.setStyle(Qt::CrossPattern); break;
  //case draw_DIAGCROSS:  qb.setStyle(Qt::DiagCrossPattern); break;
  //}
  //painter->setBrush(qb);
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetLineStyle( int s )
{
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetLineWidth( double w )
{
  // GraSetLineWidth(w);
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetMarkType( int mark )
{
  switch( mark )
  {
  default:
    mark = draw_POINT;
  case draw_POINT:
    SetMarkSize( 1 );
    break;

  case draw_STAR:
  case draw_PLUS:
    SetMarkSize( 6 );
    break;

  case draw_X:
  case draw_CIRCLE:
  case draw_HOLLOW_CIRCLE:
  case draw_HOLLOW_DIAMOND:
  case draw_DIAMOND:
    SetMarkSize( 5 );
    break;

  case draw_BOX:
  case draw_HOLLOW_BOX:
    SetMarkSize( 4 );
    break;
  }
  gra_mark_type = mark;
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetMarkSize( double size )
{
  gra_mark_size = (int) size;
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetLineColor( long int c )
{
  double r, g, b;
  decodeColor(c, &r, &g, &b);
  glColor3d (r, g, b);
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetMarkColor( long int c )
{
  double r, g, b;
  decodeColor(c, &r, &g, &b);
  glColor3d (r, g, b);
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetFillColor( long int c )
{
  double r, g, b;
  decodeColor(c, &r, &g, &b);
  glColor3d (r, g, b);
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::SetTextColor( long int c )
{
  double r, g, b;
  decodeColor(c, &r, &g, &b);
  glColor3d (r, g, b);
}

//
//////////////////////////////////////////////////////////////////////////
void 
aplicationdraw::decodeColor( long int c, double *r, double *g, double *b )
{
  *r = (double)( 0xFF & ( c >> 16 ) ) / 255.0;
  *g = (double)( 0xFF & ( c >> 8  ) ) / 255.0;
  *b = (double)( 0xFF & ( c >> 0  ) ) / 255.0;
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::wcCanvas( double xwc, double ywc, double zwc, 
                               double *xdc, double *ydc, double*zdc )
{
  GLdouble modelMatrix[16];
  GLdouble projeMatrix[16];
  GLint    viewport[4];

  glGetDoublev( GL_MODELVIEW_MATRIX,  modelMatrix );
  glGetDoublev( GL_PROJECTION_MATRIX, projeMatrix );
  glGetIntegerv( GL_VIEWPORT, viewport );

  gluProject( xwc, ywc, zwc, modelMatrix, projeMatrix, viewport, xdc, ydc, zdc );
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::begin()
{
  glBegin( GL_LINE_STRIP );
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::addVertex( double x, double y, double z )
{
  glVertex2d( x, y);
}

//
//////////////////////////////////////////////////////////////////////////
void aplicationdraw::end()
{
  glEnd( );
}
/* ================================ _gra2dArc ============================= */

static void _gra2dArc(int xc, int yc, int width, int height, double angle1, double angle2)
{
  long int a=width/2;              /* semi-eixo horizontal */
  long int b=height/2;             /* semi-eixo vertical */
  long int x;                      /* (x, y) percorre um quadrante da... */
  long int y;                      /* ...elipse, os outros sao simetricos */
  long int px1;                    /* coordenadas dos pontos simetricos */
  long int px2;                    /* coordenadas dos pontos simetricos */
  long int py1;                    /* coordenadas dos pontos simetricos */
  long int py2;                    /* coordenadas dos pontos simetricos */
  long int F;                      /* valor do ponto na funccao */
  long int DFx, DFy;               /* incremento da funccao */
  long int gx, gy;                 /* gradiente */
  int big = 0;                     /* Maior que 180o ? */

  /* constantes precalculadas */
  const long int _a2 = a*a;
  const long int _b2 = b*b;
  const long int _2a2 = 2*_a2;
  const long int _2b2 = 2*_b2;
  const long int _4a2 = 2*_2a2;
  const long int _4b2 = 2*_2b2;
  const long int _8a2 = 2*_4a2;
  const long int _8b2 = 2*_4b2;

  /* variaveis para o criterio de pertinencia */
  double x1, y1, x2, y2;
  double ta1, tb1, tc1, td1, ta2, tb2, tc2, td2;
  /* ta1 = y1 * x - x1 * y; ta2 = - y2 * x + x2 * y */
  double angled; /* Variacao entre o angulo 2 e o 1 */

  reduce(angle1);
  reduce(angle2);
  angled = angle2 - angle1;
  reduce(angled);

  if (angled > 180 || angle2 == angle1)
  {
    double anglet = angle1;
    angle1 = angle2;
    angle2 = anglet;
    big = 1;
  }

  /* inicializa o ponto final e o inicial */
  x1 = a*cos(angle1/GRA_RAD2DEG);
  x2 = a*cos(angle2/GRA_RAD2DEG);

  y1 = b*sin(angle1/GRA_RAD2DEG);
  y2 = b*sin(angle2/GRA_RAD2DEG);

  /* checa quem eh o maior semi-eixo */
  if (b>a) 
  {
    x = 0;
    px1 = xc;
    px2 = xc;
    y = b;
    py1 = yc + b;
    py2 = yc - b;

    ta1 = tb1 = x1 * y;
    tc1 = td1 = - ta1;
    ta2 = tb2 = x2 * y;
    tc2 = td2 = - ta2;

    /* inicializa a funcao de erro */
    /* F(x, y) = _a2*y2 + _b2*x2 - _a2*_b2, em (1, b - 0.5) */
    F = _4b2 - _4a2*_b2 + _a2*(2*b-1)*(2*b-1);

    /* inicializa o gradiente */
    gx = _2b2;
    gy = _a2*(2*b-1);

    /* inicializa o incremento da funccao implicita */    
    DFx = _4b2*(2*x-1) + _4b2;
    DFy = _4a2 - _4a2*(2*y+1);

    /* coloca os primeiros pontos */
    Two();

    /* desenha o primeiro octante */
    while (gx<gy) {
      /* se o midpoint estiver fora... */
      if (F>0) {
        y--;
        py1--;
        py2++;
        gy -= _2a2;
        DFy += _8a2;
        F += DFy;
        ta1 -= x1; tb1 -= x1; tc1 += x1; td1 += x1;
        ta2 -= x2; tb2 -= x2; tc2 += x2; td2 += x2;
      }
      x++;
      px1++;
      px2--;
      gx += _2b2;
      DFx += _8b2;
      F += DFx;
      ta1 -= y1; tb1 += y1; tc1 += y1; td1 -= y1;
      ta2 -= y2; tb2 += y2; tc2 += y2; td2 -= y2;
      Four();
    }

    /* ajusta F para o segundo octante */
    F = _b2*(2*x+1)*(2*x+1) + _4a2*(y-1)*(y-1) - _4a2*_b2;
    DFx = _4b2*(2*x-1) + _4b2;
    DFy =  _4a2 - _8a2*y;

    /* desenha o segundo octante */
    while (y>1) {
      if (F<0) {
        x++;
        px1++;
        px2--;
        DFx += _8b2;
        F += DFx;
        ta1 -= y1; tb1 += y1; tc1 += y1; td1 -= y1;
        ta2 -= y2; tb2 += y2; tc2 += y2; td2 -= y2;
      }
      y--;
      py1--;
      py2++;
      DFy += _8a2;
      F += DFy;
      ta1 -= x1; tb1 -= x1; tc1 += x1; td1 += x1;
      ta2 -= x2; tb2 -= x2; tc2 += x2; td2 += x2;
      if (x>0) {
        Four();
      }
      else {
        Two();
      }
    }

    /* desenha o ultimo ponto */
    if (F<0) {
      px1++;
      px2--;
      ta1 -= y1; tb1 += y1; tc1 += y1; td1 -= y1;
      ta2 -= y2; tb2 += y2; tc2 += y2; td2 -= y2;
    }
    py1--;
    py2++;
    ta1 -= x1; tb1 -= x1; tc1 += x1; td1 += x1;
    ta2 -= x2; tb2 -= x2; tc2 += x2; td2 += x2;
    if (px1 != px2) {
      Two();
    }
    else {
      One();
    }
  }

  else {
    x = a;
    px1 = xc + a;
    px2 = xc - a;
    y = 0;
    py1 = yc;
    py2 = yc;

    ta1 = td1 = - y1 * x;
    tb1 = tc1 = - ta1;
    ta2 = td2 = - y2 * x;
    tb2 = tc2 = - ta2;

    /* inicializa a funcao de erro */
    /* F(x, y) = _a2*y2 + _b2*x2 - _a2*_b2, em (a - 0.5, 1) */
    F = _4a2 - _4b2*_a2 + _b2*(2*a-1)*(2*a-1);

    /* inicializa o gradiente */
    gy = _2a2;
    gx = _b2*(2*a-1);

    /* coloca os primeiros pontos */
    Two();

    /* desenha o primeiro octante */
    while (gy<gx) {
      /* se o midpoint estiver fora... */
      if (F>0) {
        x--;
        px1--;
        px2++;
        gx -= _2b2;
        F += _4b2 - _4b2*(2*x+1);
        ta1 += y1; tb1 -= y1; tc1 -= y1; td1 += y1;
        ta2 += y2; tb2 -= y2; tc2 -= y2; td2 += y2;
      }
      y++;
      py1++;
      py2--;
      gy += _2a2;
      F += _8a2*y + _4a2;
      ta1 += x1; tb1 += x1; tc1 -= x1; td1 -= x1;
      ta2 += x2; tb2 += x2; tc2 -= x2; td2 -= x2;
      Four();
    }

    /* ajusta F para o segundo octante */
    F = _a2*(2*y+1)*(2*y+1) + _4b2*(x-1)*(x-1) - _4a2*_b2;

    /* desenha o segundo octante */
    while (x>1) {
      if (F<0) {
        y++;
        py1++;
        py2--;
        F += _4a2*(2*y-1) + _4a2;
        ta1 += x1; tb1 += x1; tc1 -= x1; td1 -= x1;
        ta2 += x2; tb2 += x2; tc2 -= x2; td2 -= x2;
      }
      x--;
      px1--;
      px2++;
      F += _4b2 - _8b2*x;
      ta1 += y1; tb1 -= y1; tc1 -= y1; td1 += y1;
      ta2 += y2; tb2 -= y2; tc2 -= y2; td2 += y2;
      if (y>0) {
        Four();
      }
      else {
        Two();
      }
    }

    /* desenha o ultimo ponto */
    if (F<0) {
      py1++;
      py2--;
      ta1 += x1; tb1 += x1; tc1 -= x1; td1 -= x1;
      ta2 += x2; tb2 += x2; tc2 -= x2; td2 -= x2;
    }
    px1--;
    px2++;
    ta1 += y1; tb1 -= y1; tc1 -= y1; td1 += y1;
    ta2 += y2; tb2 -= y2; tc2 -= y2; td2 += y2;
    if (py1 != py2) {
      Two();
    }
    else {
      One();
    }
  }
}

/* ================================ _gra2dSector ============================= */

static void _gra2dSector( int xc, int yc, int width, int height, double angle1, double angle2 )
{
  long int a=width/2;              /* semi-eixo horizontal */
  long int b=height/2;             /* semi-eixo vertical */
  long int x;                      /* (x, y) percorre um quadrante da... */
  long int y;                      /* ...elipse, os outros sao simetricos */
  long int px1;                    /* coordenadas dos pontos simetricos */
  long int px2;                    /* coordenadas dos pontos simetricos */
  long int py1;                    /* coordenadas dos pontos simetricos */
  long int py2;                    /* coordenadas dos pontos simetricos */
  long int F;                      /* valor do ponto na funccao */
  long int DFx, DFy;               /* incremento da funccao */
  long int gx, gy;                 /* gradiente */
  int big = 0;                     /* Maior que 180o ? */
  int old_line_style, old_line_width;

  /* constantes precalculadas */
  const long int _a2 = a*a;
  const long int _b2 = b*b;
  const long int _2a2 = 2*_a2;
  const long int _2b2 = 2*_b2;
  const long int _4a2 = 2*_2a2;
  const long int _4b2 = 2*_2b2;
  const long int _8a2 = 2*_4a2;
  const long int _8b2 = 2*_4b2;

  /* variaveis para o criterio de pertinencia */
  double x1, y1, x2, y2;
  double ta1, tb1, tc1, td1, ta2, tb2, tc2, td2;
  /* ta1 = y1 * x - x1 * y; ta2 = - y2 * x + x2 * y */
  double angled; /* Variacao entre o angulo 2 e o 1 */

  /* variaveis pras retas */
  double r1x, r1y, r2x, r2y;            /* posicao x e y nas retas 1 e 2 */
  double r1k, r2k;

  old_line_style = 1; /* cdLineStyle(CD_CONTINUOUS); */
  old_line_width = 1; /*cdLineWidth(1); */

  reduce(angle1);
  reduce(angle2);
  angled = angle2 - angle1;
  reduce(angled);

  r1x = r1y = r2x = r2y = 0.0;

  if (angled > 180.0 || angle2 == angle1)
  {
    double anglet = angle1;
    angle1 = angle2;
    angle2 = anglet;
    big = 1;
  }

  /* inicializa o ponto final e o inicial */
  x1 = a*cos(angle1/GRA_RAD2DEG);
  x2 = a*cos(angle2/GRA_RAD2DEG);

  y1 = b*sin(angle1/GRA_RAD2DEG);
  y2 = b*sin(angle2/GRA_RAD2DEG);

  x = 0;
  px1 = xc;
  px2 = xc;
  y = b;
  py1 = yc + b;
  py2 = yc - b;

  ta1 = tb1 = x1 * y;
  tc1 = td1 = - ta1;
  ta2 = tb2 = x2 * y;
  tc2 = td2 = - ta2;

  /* inicializa a funcao de erro */
  /* F(x, y) = _a2*y2 + _b2*x2 - _a2*_b2, em (1, b - 0.5) */
  F = _4b2 - _4a2*_b2 + _a2*(2*b-1)*(2*b-1);
  /* inicializa o gradiente */
  gx = _2b2;
  gy = _a2*(2*b-1);

  /* inicializa o incremento da funccao implicita */    
  DFx = _4b2*(2*x-1) + _4b2;
  DFy = _4a2 - _4a2*(2*y+1);

  r1k = x1 / y1;
  r2k = x2 / y2;

  /* Interseccao da linha horizontal atual com as retas */
  if (y1 != 0)
  {
    r1y = (y1 > 0) ? y : -y;
    r1x = r1y * r1k;      
    if ((int)r1x + xc >= px1 || (int)r1x + xc <= px2) /* nao intersectou */
      r1y++;
  }
  if (y2 != 0)
  {
    r2y = (y2 > 0) ? y : -y;
    r2x = r2y * r2k;      
    if ((int)r2x + xc >= px1 || (int)r2x + xc <= px2) /* nao intersectou */
      r2y++;
  }

  /* coloca os primeiros pontos */
  Two();

  /* desenha o primeiro octante */
  while (gx<gy) {
    /* se o midpoint estiver fora... */
    if (F>0) {
      LinesX();

      y--;
      py1--;
      py2++;
      gy -= _2a2;
      DFy += _8a2;
      F += DFy;
      ta1 -= x1; tb1 -= x1; tc1 += x1; td1 += x1;
      ta2 -= x2; tb2 -= x2; tc2 += x2; td2 += x2;
      if (y1 != 0)
      {
        r1y = (y1 > 0) ? y : -y;
        r1x = r1y * r1k;      
        if ((int)r1x + xc >= px1 || (int)r1x + xc <= px2) /* nao intersectou */
          r1y++;
      }
      if (y2 != 0)
      {
        r2y = (y2 > 0) ? y : -y;
        r2x = r2y * r2k;      
        if ((int)r2x + xc >= px1 || (int)r2x + xc <= px2) /* nao intersectou */
          r2y++;
      }
    }
    x++;
    px1++;
    px2--;
    gx += _2b2;
    DFx += _8b2;
    F += DFx;
    ta1 -= y1; tb1 += y1; tc1 += y1; td1 -= y1;
    ta2 -= y2; tb2 += y2; tc2 += y2; td2 -= y2;
  }

  LinesX();
  /* ajusta F para o segundo octante */
  F = _b2*(2*x+1)*(2*x+1) + _4a2*(y-1)*(y-1) - _4a2*_b2;
  DFx = _4b2*(2*x-1) + _4b2;
  DFy =  _4a2 - _8a2*y;

  /* desenha o segundo octante */
  while (y>1) {
    if (F<0) {
      x++;
      px1++;
      px2--;
      DFx += _8b2;
      F += DFx;
      ta1 -= y1; tb1 += y1; tc1 += y1; td1 -= y1;
      ta2 -= y2; tb2 += y2; tc2 += y2; td2 -= y2;
    }
    y--;
    py1--;
    py2++;
    DFy += _8a2;
    F += DFy;
    ta1 -= x1; tb1 -= x1; tc1 += x1; td1 += x1;
    ta2 -= x2; tb2 -= x2; tc2 += x2; td2 += x2;
    if (y1 != 0)
    {
      r1y = (y1 > 0) ? y : -y;
      r1x = r1y * r1k;      
      if ((int)r1x + xc >= px1 || (int)r1x + xc <= px2) /* nao intersectou */
        r1y++;
    }
    if (y2 != 0)
    {
      r2y = (y2 > 0) ? y : -y;
      r2x = r2y * r2k;      
      if ((int)r2x + xc >= px1 || (int)r2x + xc <= px2) /* nao intersectou */
        r2y++;
    }
    LinesX();
  }

  /* desenha o ultimo ponto */
  if (F<0) {
    px1++;
    px2--;
    ta1 -= y1; tb1 += y1; tc1 += y1; td1 -= y1;
    ta2 -= y2; tb2 += y2; tc2 += y2; td2 -= y2;
  }
  py1--;
  py2++;
  ta1 -= x1; tb1 -= x1; tc1 += x1; td1 += x1;
  ta2 -= x2; tb2 -= x2; tc2 += x2; td2 += x2;
  LinesX();

  /* desenha o ultimo ponto */
  if (F<0) {
    py1++;
    py2--;
    ta1 += x1; tb1 += x1; tc1 -= x1; td1 -= x1;
    ta2 += x2; tb2 += x2; tc2 -= x2; td2 -= x2;
  }
  px1--;
  px2++;
  ta1 += y1; tb1 -= y1; tc1 -= y1; td1 += y1;
  ta2 += y2; tb2 -= y2; tc2 -= y2; td2 += y2;
  LineX();

  //GraSetLineStyle(old_line_style);
  //GraSetLineWidth(old_line_width);
}

/* =================== GraSetRasterDspMode ==================== */
void GraSetRasterDspMode( void )
{
  GLint v[4];

  glGetIntegerv( GL_VIEWPORT, v );
  glMatrixMode( GL_PROJECTION );
  glPushMatrix( );
  glLoadIdentity( );

  gluOrtho2D( 0.0, (GLdouble) ( v[2] - 1 ), 0.0, (GLdouble) ( v[3] - 1 ) );

  glMatrixMode( GL_MODELVIEW );
  glPushMatrix( );
  glLoadIdentity( );
}

/* ================== GraResetRasterDspMode =================== */
void GraResetRasterDspMode( void )
{
  glMatrixMode( GL_PROJECTION );
  glPopMatrix( );

  glMatrixMode( GL_MODELVIEW );
  glPopMatrix( );
}

